#include "instructions.hpp"


namespace risco {


int token_code[500];
int code_token[500];
const char* token_str[500] = { 0 };


void init()
{
  static bool first = true;

  if (first) {
    first = false;
  }
  else {
    return;
  }


  #define op(name, cod) \
    token_str[T##name] = #name; \
    token_code[T##name] = cod; \
    code_token[cod] = T##name

  
  // token    T1,T0,C4,C3,C2,C1,C0
  
  op(add,     0b0000000);
  op(addc,    0b0000010);
  op(sub,     0b0000101);
  op(subc,    0b0000111);
  op(subr,    0b0001001);
  op(subrc,   0b0001011);

  op(and,     0b0001111);
  op(or,      0b0001110);
  op(xor,     0b0001101);

  op(rll,     0b0010000);
  op(rllc,    0b0010001);
  op(rla,     0b0010010);
  op(rlac,    0b0010011);

  op(rrl,     0b0010100);
  op(rrlc,    0b0010101);
  op(rra,     0b0010110);
  op(rrac,    0b0010111);

  op(sll,     0b0011000);
  op(sllc,    0b0011001);
  op(sla,     0b0011010);
  op(slac,    0b0011011);

  op(srl,     0b0011100);
  op(srlc,    0b0011101);
  op(sra,     0b0011110);
  op(srac,    0b0011111);

  op(ld,      0b1001011);
  op(st,      0b1011011);

  op(ldpri,   0b1001111);
  op(ldpoi,   0b1001101);
  op(ldpod,   0b1001100);

  op(stpri,   0b1011111);
  op(stpoi,   0b1011101);
  op(stpod,   0b1011100);

  op(jmp,     0b0111111);
  op(jmpns,   0b0110001);
  op(jmpcs,   0b0110010);
  op(jmpos,   0b0110100);
  op(jmpzs,   0b0111000);
  op(jmpge,   0b0110011);
  op(jmpgt,   0b0110110);
  op(jmpeq,   0b0111100);
  op(jmpfl,   0b0100000);
  op(jmpnn,   0b0100001);
  op(jmpnc,   0b0100010);
  op(jmpno,   0b0100100);
  op(jmpnz,   0b0101000);
  op(jmplt,   0b0100011);
  op(jmple,   0b0100110);
  op(jmpne,   0b0101100);

  op(sr,      0b1111111);
  op(srns,    0b1110001);
  op(srcs,    0b1110010);
  op(sros,    0b1110100);
  op(srzs,    0b1111000);
  op(srge,    0b1110011);
  op(srgt,    0b1110110);
  op(sreq,    0b1111100);
  op(srfl,    0b1100000);
  op(srnn,    0b1100001);
  op(srnc,    0b1100010);
  op(srno,    0b1100100);
  op(srnz,    0b1101000);
  op(srlt,    0b1100011);
  op(srle,    0b1100110);
  op(srne,    0b1101100);

  op(syscall, 0b0000001);  // between 'add' and 'addc'

  #undef op
}


const char* instruction_str(int op)
{
  init();
  return token_str[op];
}


int instruction_code(int op)
{
  init();
  return token_code[op];
}


int code_instruction(int code)
{
  init();
  return code_token[code];
}


bool is_ldp(int op)
{
  switch (op) {
    case Tldpri:
    case Tldpoi:
    case Tldpod:
      return true;

    default:
      return false;
  }
}


bool is_stp(int op)
{
  switch (op) {
    case Tstpri:
    case Tstpoi:
    case Tstpod:
      return true;

    default:
      return false;
  }
}


bool is_syscall(int op)
{
  return op == Tsyscall;
}


}
